import { onMounted, reactive, ref, watch } from 'vue'
import { evalPropChain } from '@/utils'
import request from '@/api'
const AXIOS_METHOD = {
  get: request.get,
  post: request.post
}
const getServeUrl = props => {
  return props.url
}
export const useState = () => {
  return reactive({
    vxeColumns: [],
    vxeDatas: [],
    selectedRowKeys: [],
    selectedRows: [],
    selectedRowsMap: {},
    loading: false,
    exportLoading: false,
    query: {},
    tableId: 'cpsVxeTable',
    paginate: {
      pageNum: 1,
      pageSize: 50,
      total: 0
    }
  })
}
export const useInitState = (props, state) => {
  const { pageSize } = props

  Object.assign(state.paginate, {
    pageNum: 1,
    pageSize: pageSize || 50,
    total: 0
  })
  Object.assign(state, {
    tableId: props.tableId || props.menuName || 'cpsVxeTable',
    selectedRowKeys: props.selectedRowKeys || [],
    vxeColumns: props.columns || [],
    localApiParams: props.apiParams
      ? JSON.parse(JSON.stringify(props.apiParams))
      : {}
  })
}
/**
 * 计算表格列宽
 * @param {*} column
 * @returns
 */
const useColumnWidth = column => {
  const { label: columnName } = column

  let fixedWidth = 0
  for (let i = 0; i < columnName.length; i++) {
    const charCode = columnName.charCodeAt(i)
    if (charCode >= 0 && charCode <= 128) {
      fixedWidth += 8
    } else {
      fixedWidth += 16
    }
  }
  // 添加两边的间距 5是误差
  fixedWidth += 16 + 5
  if (fixedWidth < 160) {
    return 160
  }
  if (fixedWidth > 320) {
    return 320
  }
  return fixedWidth
}

/**
 * 获取表格数据
 */
const useGetTableDatas = (props, state) => {
  props.loading && (state.loading = true)
  const { hasPaginate, beforeReqLoad, afterRespLoad, method } = props
  let curPaginate = hasPaginate ? state.paginate : {}
  const serveParams = {
    ...curPaginate,
    ...state.localApiParams,
    ...state.query
  }
  if (beforeReqLoad) {
    beforeReqLoad(serveParams)
  }

  const fetchData = async () => {
    const resp = await AXIOS_METHOD[method.toLowerCase()](
      getServeUrl(props),
      serveParams
    )
    const { code, data } = resp

    if (code === 200) {
      if (Object.prototype.toString.call(data) === '[object Object]') {
        state.vxeDatas =
          data.records || evalPropChain(resp, props.respField) || []
      } else {
        state.vxeDatas = data || []
      }
      state.paginate.total = data?.total || 0
    } else {
      state.vxeDatas = []
    }
    if (afterRespLoad) {
      afterRespLoad(state.vxeDatas)
    }
    state.loading = false
  }
  fetchData()
}
/**
 * 处理表格的相关操作问题
 */
const useTableOperate = (props, state, emits, tableDom) => {
  // 多选框
  const handleSelectionChange = multipleSelection => {
    const $table = tableDom.value

    if ($table) {
      state.selectedRowsMap[state.paginate.pageNum] = multipleSelection
    }
  }
  /**
   * 获取单选复选的值
   * @param {*} val
   */
  const getCheckboxRecords = val => {
    state.selectedRowKeys = []
    state.selectedRows = []
    if (val) {
      const keys = Object.keys(val)
      state.selectedRows = keys.reduce((prev, cur) => {
        return [...prev, ...val[cur]]
      }, [])
      state.selectedRowKeys = state.selectedRows.map(item => item[props.rowKey])
    }
  }
  // 取消选择
  const onCancelSelect = () => {
    const $table = tableDom.value
    state.selectedRowKeys = []
    state.selectedRows = []
    state.selectedRowsMap = {}
    if ($table) {
      $table?.clearSelection()
    }
  }
  // 导出
  const exportExcel = () => {
    state.exportLoading = true
    emits(
      'export',
      {
        ...props.apiParams,
        ...state.query
      },
      state.paginate
    )
    setTimeout(() => {
      state.exportLoading = false
    }, 1000)
  }
  // 刷新页面，保留用户操作
  const refresh = apiParams => {
    if (
      apiParams &&
      Object.prototype.toString.call(apiParams) === '[object Object]'
    ) {
      state.localApiParams = apiParams
    }
    props.url && useGetTableDatas(props, state)
    onCancelSelect()
    emits('refresh')
  }
  // 重置页面
  const reset = apiParams => {
    if (
      apiParams &&
      Object.prototype.toString.call(apiParams) === '[object Object]'
    ) {
      state.localApiParams = apiParams
    }
    state.paginate.pageNum = 1
    state.query = { sortList: [] }
    onCancelSelect()
    props.url && useGetTableDatas(props, state)
    emits('reset')
  }
  // 分页
  const changePage = (page, isCurrent) => {
    isCurrent && (state.paginate.pageNum = page)
    !isCurrent && (state.paginate.pageSize = page)
    useGetTableDatas(props, state)
  }
  /**
   * 计算列宽
   * @param {*} item
   * @returns
   */
  const calcColumnWidth = item => {
    if (item.width || item.minWidth) {
      return item.width || item.minWidth
    }
    if (props.isCustomWidth) {
      return useColumnWidth(item, props)
    }
    return 'auto'
  }
  return {
    handleSelectionChange,
    onCancelSelect,
    exportExcel,
    refresh,
    reset,
    changePage,
    getCheckboxRecords,
    calcColumnWidth
  }
}

/**
 * 处理表格watch
 * @param {*} props
 * @param {*} emits
 */
const useTableWatchData = (props, state, emits) => {
  const { getCheckboxRecords } = useTableOperate(props, state, emits)
  // 双向绑定当前页的表格数据
  watch(
    () => state.vxeDatas,
    val => {
      emits('update:value', val)
    },
    {
      deep: true
    }
  )
  watch(
    () => props.value,
    val => {
      state.vxeDatas = val || []
    },
    {
      immediate: true,
      deep: true
    }
  )
  watch(
    () => props.columns,
    val => {
      if (val) {
        state.vxeColumns = val
      }
    },
    {
      immediate: true,
      deep: true
    }
  )
  watch(
    () => state.selectedRowsMap,
    val => {
      getCheckboxRecords(val)
      emits('change', state.selectedRowKeys, state.selectedRows)
    },
    {
      deep: true
    }
  )
  watch(
    () => props.loading,
    val => {
      state.loading = val
    },
    {
      immediate: true
    }
  )
}
/**
 * 处理表格挂载
 * @param {*} props
 */
const useTableMounted = (props, state) => {
  const { url, immediate } = props
  onMounted(() => {
    useInitState(props, state)
    url && immediate && useGetTableDatas(props, state)
  })
}

export const useTable = (props, emits) => {
  const tableDom = ref(null)
  const state = useState()
  useTableWatchData(props, state, emits)
  useTableMounted(props, state)

  return {
    tableDom,
    state,
    ...useTableOperate(props, state, emits, tableDom)
  }
}
